/* 
 * Copyright 2011 kOSMik.
 * This file is part of kOSMik.
 * 
 * kOSMik is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * kOSMik is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with kOSMik.  If not, see <http://www.gnu.org/licenses/>.
 *  
 * kOSMik:
 * Open Street Map - Editor.
 * http://code.google.com/p/swp-dv-ws2010-osm-2/
 */

package de.fuberlin.kosmik.export;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import android.os.Bundle;
import android.util.Log;
import de.fuberlin.kosmik.data.dao.Poi;
import de.fuberlin.kosmik.data.dao.Point;
import de.fuberlin.kosmik.log.Constants;

/**
 * Create GPX complaint XML-Strings from our DAO Model and write them into the
 * xmlWriter.
 * 
 * @author Simon
 */
public class GpxWriter {

	private static final String HEADER = "<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" version=\"1.1\" creator=\"osmtracker-android\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd \">"; // header
	// unclean
	private static final String TRACKPOINT = "trkpt"; // simple point
	private static final String WAYPOINT = "wpt"; // POI
	private static final String TIME = "time";
	private static final String LATITUDE = "lat";
	private static final String LONGITUDE = "lon";
	private static final String NAME = "name";
	private static final String ROOT = "gpx";
	private static final String TRACK = "trk";
	private static final String TRACK_SEGMENT = "trkseg";
	private final XmlWriter xmlWriter;

	/**
	 * Implicitly writes declaration and header.
	 * 
	 * @param xmlWriter fully initialized XML writer.
	 */
	public GpxWriter(XmlWriter xmlWriter) {
		this.xmlWriter = xmlWriter;
		xmlWriter.declaration();
		xmlWriter.content(HEADER);
	}

	/**
	 * Write the entire track (means the entire points) as one tracksegment.
	 * 
	 * @param track name of the track.
	 * @param trackPoints all the points associated with this track.
	 */
	public void writeTrack(String track, Collection<Point> trackPoints) {
		Log.d(Constants.TAG, "[GPX WRITER] WRITING TRACK");
		xmlWriter.element(TRACK);
		xmlWriter.element(NAME);
		xmlWriter.content(track);
		xmlWriter.endElement(NAME);

		xmlWriter.element(TRACK_SEGMENT);

		for (Point trackPoint : trackPoints) {
			writeTrackPoint(trackPoint);
			// Log.d(Constants.TAG, "[GPX WRITER] WRITING POINT WITH LATITUDE="+
			// trackPoint.lat);
		}

		xmlWriter.endElement(TRACK_SEGMENT);
		xmlWriter.endElement(TRACK);
	}

	/**
	 * Write a waypoint with all attributes.
	 * 
	 * @param wayPoint the waypoint to write.
	 */
	public void writeWayPoint(Poi wayPoint) {
		final Bundle nestedElements = wayPoint.values;
		writePoint(WAYPOINT, wayPoint, nestedElements);
	}

	// <trkpt
	// lat="latitudeType"
	// lon="longitudeType">
	// <time> xsd:dateTime </time>
	// </trkpt>
	private void writeTrackPoint(Point trackPoint) {

		Bundle nestedElements = new Bundle(1); // only time
		nestedElements.putString(TIME, TypeConverter.convertTime(trackPoint.timestamp));
		writePoint(TRACKPOINT, trackPoint, nestedElements);
	}

	// <TYPE
	// lat="latitudeType"
	// lon="longitudeType">
	// <nestedElement>nestedElement value</nestedElement>
	// ...
	// <nestedElement>nestedElement value</nestedElement>
	// </TYPE>
	private void writePoint(String type, Point point, Bundle nestedElements) {

		xmlWriter.elementWithAttributes(type, putLocationInBundle(point));

		for (String key : nestedElements.keySet()) {
			Log.d(Constants.TAG, "[GPXWRITER] NESTED ELEMENT: KEY= " + key + " VALUE="
					+ nestedElements.getString(key));
			xmlWriter.element(key);
			xmlWriter.content(nestedElements.getString(key));
			xmlWriter.endElement(key);
		}
		xmlWriter.endElement(type);
	}

	/**
	 * Close the root entry.
	 */
	public void closeRoot() {
		xmlWriter.endElement(ROOT);
		xmlWriter.finish();
	}

	private Map<String, String> putLocationInBundle(Point location) {
		HashMap<String, String> retVal = new HashMap<String, String>(2);
		retVal.put(LONGITUDE, Double.toString(location.lng));
		retVal.put(LATITUDE, Double.toString(location.lat));
		return retVal;
	}
}
